/***************************************************
  mainwindow的构造及析构函数。解析数据包并操作数据库
  *********************************************/
#include "AdapterSerialPort.h"
#include "macro.h"
#include <QMessageBox>
#include <QtSql>
#include <QUdpSocket>

AdapterSerialPort::AdapterSerialPort(QWidget *parent)
: QMainWindow(parent)
{  

    timerForKeepDBConnect=new QTimer(this);
    myPortSettings=new PortSettings();
    myPortName=new QString();
    //on_settingsBtn_clicked();// 打开串口设置对话框

    setupUi(this);
    Qt::WindowFlags flags =Qt::Widget|Qt::CustomizeWindowHint|Qt::WindowMinMaxButtonsHint;
    setWindowFlags(flags);

    textEdit->setReadOnly(true);
    closeComBtn->setEnabled(false); //开始“关闭串口”按钮不可用
    sendMsgBtn->setEnabled(false); //开始“发送数据”按钮不可用
    temp=new QByteArray; //存放串口读入的数据
    udpSocket=new QUdpSocket(this);
    udpSocket->bind(QHostAddress::Any,dataBaseComUdpPort);
    connect(udpSocket,SIGNAL(readyRead()),this,SLOT(readUDPPacket()));

}


AdapterSerialPort::~AdapterSerialPort()
{
    //delete timer;
 delete myPortSettings;
 delete myPortName;
 delete temp;

 if(myCom)
 {
     myCom->close();
     myCom->deleteLater();
 }
 myPortSettings=NULL;myPortName=NULL;temp=NULL;
 myCom=NULL;
}


void    AdapterSerialPort::packetAnalyze(bool isFromUDP)
{
    bool ok;
    //现在temp的大小为实际数据字节数的2倍
    QString s=*temp;
    /***************************************************************
      协议分析模式,数据写入数据库。
      **************************************************************/
    if(!checkBoxNor->isChecked())
    {
        if(checkBoxDebug->isChecked())
        {
            textEdit->append("pakcet is: "+s);
        }

        if(temp->size()>Max_Packet_Size)
            temp->clear();

        while(temp->size()>Data_Pos*2)
        {
            if (!temp->startsWith(HEADER))
            {
                temp->clear();
                return;
            }
           if(temp->size()>Data_Pos*2)
            {
                QByteArray hexPktType=temp->mid(PktType_Pos*2,PktType_Size*2);
                QByteArray hexType=temp->mid(Type_Pos*2,Type_Size*2);
                QByteArray byteArrayLen;

                for(int n=0; n<Len_Size*2;  n++  )
                    byteArrayLen.append(temp->at(n+Len_Pos*2));

                packetLen=byteArrayLen.toUInt(&ok,16)*2+8;

                for(int n=0;n<temp->size();n+=2)
                {
                    s.insert(3*n/2," ");
                }
                if( (unsigned int)(temp->size())>=packetLen ) //长度有效
                {
                    if(checkBoxAutoScroll->isChecked())
                    {
                        textEdit->append(s);
                        if(checkBoxAutoScroll->isChecked())
                            textEdit->moveCursor(QTextCursor::End);
                    }
                    if(hexType.toUInt(&ok,16)==TypeDown) //下行数据的处理
                    {
                        emit sigInfo(tr("收到一个下行命令，即将通过串口转发给sink节点"));
                        myCom->write(QByteArray::fromHex(temp->mid(0,packetLen))); //如果是命令或命令ACK类型的包，则转发给节点
                        temp->remove(0,packetLen);
                        continue;
                    }
                    else if(hexType.toUInt(&ok,16)==TypeUp) //上行数据
                    {
                        emit sigPacketNodeToServer(QByteArray::fromHex(temp->mid(0,packetLen)),QHostAddress(aServerIP),dataBaseComUdpPort,false);
                        temp->remove(0,packetLen);
                        continue;
                    }
                    else  //Type字段错误，清空
                    {
                        temp->clear();
                        return;
                    }
                }
                else  //还没有完整的包到，先跳出while，等待新数据
                    break;
            }
       } //while 结束

        if(temp->size()>Max_Packet_Size)
            temp->clear();
    }//协议分析模式结束
    /******************************************************************
      普通的串口助手模式，只显示接收到的数据，不分析
      ****************************************************************/
    else
    {
        for(int n=0;n<temp->size();n+=2)
        {
            s.insert(3*n/2," ");
        }
        textEdit->append(s);
        if(checkBoxAutoScroll->isChecked())
            textEdit->moveCursor(QTextCursor::End);
         temp->clear();
    }//普通的串口助手模式结束
}

void AdapterSerialPort::readUDPPacket()
{
    QByteArray packet;
    QHostAddress host;
    quint16 port;
    temp->clear();

    /***************读取UDP数据包****************************/
    do
   {
     packet.resize(udpSocket->pendingDatagramSize());
     udpSocket->readDatagram(packet.data(),packet.size(),&host,&port); //读数据包

     if(packet.startsWith("ERR")||packet.startsWith("WARN")||packet.startsWith("INF")||packet.startsWith("EVENT"))
     {
         emit sigInfo("Info from server"+packet);
         if(checkBoxShowInfo->isChecked())
             textEdit->append(">:"+packet);
         packet.clear();
         continue;
     }
     temp->append(packet.toHex());
     packet.clear();
     packetAnalyze(true); //分析来自UDP的包。可能是服务器下发的对节点的控制命令
     qApp->processEvents(QEventLoop::ExcludeSocketNotifiers);
   }while (udpSocket->hasPendingDatagrams());

}

void AdapterSerialPort::readMyCom()     //读串口函数
{
    //temp->clear();
    temp->append(myCom->readAll().toHex());
    packetAnalyze(false); //分析来自非UDP的包。
}


void AdapterSerialPort::on_pushButtonHide_clicked()
{
    hide();
}
